package huxibianjie.com.lbscandroid.pedomemter;

import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import huxibianjie.com.lbscandroid.Constants;
import huxibianjie.com.lbscandroid.R;
import huxibianjie.com.lbscandroid.model.StepData;
import huxibianjie.com.lbscandroid.ui.new_activity.HomeActivity;
import huxibianjie.com.lbscandroid.ui.new_activity.StepListener;
import huxibianjie.com.lbscandroid.util.Constant;
import huxibianjie.com.lbscandroid.util.DbUtils;
import huxibianjie.com.lbscandroid.util.LogUtils;
import huxibianjie.com.lbscandroid.util.MyLog;

/**
 * 计步服务
 * Created by lenovo on 2017/1/17.
 */
@TargetApi(Build.VERSION_CODES.CUPCAKE)
public class StepService extends Service implements SensorEventListener {
    private final String TAG = "TAG_StepService";   //"StepService";
    //默认为30秒进行一次存储
    private static int duration = 3000;
    private static String CURRENTDATE = "";   //当前的日期
    private SensorManager sensorManager;    //传感器管理者
    private StepDetector stepDetector;
    private NotificationManager nm;
    private NotificationCompat.Builder builder;
    //广播
    private BroadcastReceiver mBatInfoReceiver;
    private PowerManager.WakeLock mWakeLock;

    //计步传感器类型 0-counter 1-detector 2-加速度传感器
    private static int stepSensor = -1;
    private List<StepData> mStepData;

    //用于计步传感器 传感器已经保存的步数
    private int previousStep;
    private boolean isNewDay = false;    //用于判断是否是新的一天，如果是新的一天则将之前的步数赋值给previousStep


    private SharedPreferences sharedPreferences;
    private SharedPreferences.Editor editor;

    @Override
    public void onCreate() {
        MyLog.e("ambit", "onCreate");
        super.onCreate();
        //初始化广播
        initBroadcastReceiver();
        new Thread(new Runnable() {
            @Override
            public void run() {
                //启动步数监测器
                startStepDetector();
            }
        }).start();
        sharedPreferences = getSharedPreferences(Constants.LAST_STEP, MODE_PRIVATE);
        editor = sharedPreferences.edit();

        if (timer != null) {
            timer.cancel();
            timer = null;
        }
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                handler.sendEmptyMessage(1);
            }
        }, 0, 1000);
    }

    private StepListener stepListener;

    public class MyBinder extends Binder {
        public void addStepInterface(StepListener stepListener) {
            StepService.this.stepListener = stepListener;
        }
    }

    private Timer timer;

    @Override
    public int onStartCommand(Intent intent, int flags, final int startId) {
        MyLog.e("ambit", "onStartCommand");
        initTodayData();
        updateNotification("今日步数:" + StepDetector.CURRENT_STEP + " 步");
        return START_STICKY;
    }

    private Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message message) {
            if (message.what == 1) {
                if (stepSensor != 0) {
                    //0传感器已经保存了不多于保存
                    save();
                }
                if (stepListener != null) {
                    stepListener.onStepListener(StepDetector.CURRENT_STEP);
                }
            }
            return false;
        }
    });

    /**
     * 获得今天的日期
     */
    private String getTodayDate() {
        Date date = new Date(System.currentTimeMillis());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(date);
    }

    /**
     * 初始化当天的日期
     */
    private void initTodayData() {
        CURRENTDATE = getTodayDate();
        //在创建方法中有判断，如果数据库已经创建了不会二次创建的
        DbUtils.createDb(this, Constant.Config.DB_NAME);
        //获取当天的数据
        List<StepData> list = DbUtils.getQueryByWhere(StepData.class, "today", new String[]{CURRENTDATE});
        if (list.size() == 0) {
            //如果获取当天数据为空，则步数为0
            StepDetector.CURRENT_STEP = 0;
            editor.putLong(Constants.LAST_STEP, 0);
            editor.commit();
            isNewDay = true;  //用于判断是否存储之前的数据，后面会用到
        } else if (list.size() == 1) {
            isNewDay = false;
            //如果数据库中存在当天的数据那么获取数据库中的步数
            if (Integer.parseInt(list.get(0).getStep()) < 0) {
                StepDetector.CURRENT_STEP = 0;
            } else {
                StepDetector.CURRENT_STEP = Integer.parseInt(list.get(0).getStep());
            }
        } else {
            Log.e(TAG, "出错了！");
            LogUtils.writeLog(this, "initTodayData  error");
        }
    }

    /**
     * 初始化广播
     */
    private void initBroadcastReceiver() {
        //定义意图过滤器
        final IntentFilter filter = new IntentFilter();
        //屏幕灭屏广播
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        //日期修改
        filter.addAction(Intent.ACTION_TIME_CHANGED);
        //关闭广播
        filter.addAction(Intent.ACTION_SHUTDOWN);
        //屏幕高亮广播
        filter.addAction(Intent.ACTION_SCREEN_ON);
        //屏幕解锁广播
        filter.addAction(Intent.ACTION_USER_PRESENT);
        //当长按电源键弹出“关机”对话或者锁屏时系统会发出这个广播
        //example：有时候会用到系统对话框，权限可能很高，会覆盖在锁屏界面或者“关机”对话框之上，
        //所以监听这个广播，当收到时就隐藏自己的对话，如点击pad右下角部分弹出的对话框
        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);

        mBatInfoReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();

                if (Intent.ACTION_SCREEN_ON.equals(action)) {
                    Log.v(TAG, "screen on");
                } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                    Log.v(TAG, "screen off");
                    save();
                    //改为60秒一存储
                    duration = 6000;
                } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
                    Log.v(TAG, "screen unlock");
                    save();
                    //改为30秒一存储
                    duration = 3000;
                } else if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
                    Log.v(TAG, "receive Intent.ACTION_CLOSE_SYSTEM_DIALOGS  出现系统对话框");
                    //保存一次
                    save();
                } else if (Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
                    Log.v(TAG, "receive ACTION_SHUTDOWN");
                    save();
                } else if (Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) {
                    Log.v(TAG, "receive ACTION_TIME_CHANGED");
                    initTodayData();
                }
            }
        };
        registerReceiver(mBatInfoReceiver, filter);
    }

    /**
     * 更新通知(显示通知栏信息)
     *
     * @param content
     */
    private void updateNotification(String content) {
        if (builder == null) {
            builder = new NotificationCompat.Builder(this);
            builder.setPriority(Notification.PRIORITY_MIN);
            PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
                    new Intent(this, HomeActivity.class), 0);
            builder.setContentIntent(contentIntent);
            builder.setSmallIcon(R.mipmap.ic_logo);
            builder.setTicker(getResources().getString(R.string.app_name));
            builder.setContentTitle(getResources().getString(R.string.app_name));
            //设置不可清除
            builder.setOngoing(true);
            builder.setContentText(content);
            Notification notification = builder.build(); //上面均为构造Notification的构造器中设置的属性
            startForeground(0, notification);
            nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            nm.notify(101, notification);
        } else {
            builder.setContentText(content);
            nm.notify(101, builder.build());
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        MyLog.e("ambit", "onBind");
//        if (messenger == null) {
//            messenger = new Messenger(new MessengerHandler());
//        }
        return new MyBinder();
    }

    private void startStepDetector() {
        if (sensorManager != null && stepDetector != null) {
            sensorManager.unregisterListener(stepDetector);
            sensorManager = null;
            stepDetector = null;
        }
        //得到休眠锁，目的是为了当手机黑屏后仍然保持CPU运行，使得服务能持续运行
        getLock(this);
        sensorManager = (SensorManager) this.getSystemService(SENSOR_SERVICE);
        //android4.4以后可以使用计步传感器
        int VERSION_CODES = Build.VERSION.SDK_INT;

        if (VERSION_CODES >= 19) {
            addCountStepListener();
        } else {
            addBasePedoListener();
        }
    }

    /**
     * 使用自带的计步传感器
     * <p>
     * 说明：
     * 开始使用这个传感器的时候很头疼，虽然它计步很准确，然而计步一开始就是5w多步，搞不懂它是怎么计算的，而且每天
     * 都在增长，不会因为日期而清除。今天灵光一闪，我脑海中飘过一个想法，会不会手机上的计步传感器是以一个月为计算周期
     * 呢？     于是乎，我打开神器QQ，上面有每天的步数，我把这个月的步数加到了一起在和手机上显示的步数进行对比，呵，
     * 不比不知道，一比吓一跳哈。就差了几百步，我猜测误差是因为QQ定期去得到计步传感器的步数，而我的引用是实时获取。要不然
     * 就是有点小误差。不过对于11W多步的数据几百步完全可以忽略。从中我可以得到下面两个信息：
     * 1.手机自带计步传感器存储的步数信息是以一个月为周期进行清算
     * 2.QQ计步使用的是手机自带的计步传感器   啊哈哈哈
     * <p>
     * <p>
     * 后来当我要改的时候又发现问题了
     * 我使用了StepDetector.CURRENT_STEP = (int)event.values[0];
     * 所以它会返回这一个月的步数，当每次传感器发生改变时，我直接让CURRENT_STEP++；就可以从0开始自增了
     * 不过上面的分析依然正确。不过当使用CURRENT_STEP++如果服务停掉计步就不准了。如果使用计步传感器中
     * 统计的数据减去之前的数据就是当天的数据了，这样每天走多少步就能准确的显示出来
     */
    private void addCountStepListener() {
        Sensor detectorSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);
        Sensor countSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
        if (countSensor != null) {
            stepSensor = 0;
            Log.v(TAG, "1 countSensor 步数传感器");
            LogUtils.writeLog(this, "1 create step_detector");
            sensorManager.registerListener(StepService.this, countSensor, SensorManager.SENSOR_DELAY_UI);
        } else if (detectorSensor != null) {
            stepSensor = 1;
            Log.v(TAG, "2 detector 步数传感器");
            LogUtils.writeLog(this, "2 create step_counter");
            sensorManager.registerListener(StepService.this, detectorSensor, SensorManager.SENSOR_DELAY_UI);
        } else {
            stepSensor = 2;
            Log.e(TAG, "Count sensor not available! 没有可用的传感器，只能用加速传感器了");
            LogUtils.writeLog(this, "3 create step_detector");
            addBasePedoListener();
        }
    }


    /**
     * 使用加速度传感器
     */
    private void addBasePedoListener() {
        //只有在使用加速传感器的时候才会调用StepDetector这个类
        stepDetector = new StepDetector(this);
        //获得传感器类型，这里获得的类型是加速度传感器
        //此方法用来注册，只有注册过才会生效，参数：SensorEventListener的实例，Sensor的实例，更新速率
        Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        sensorManager.registerListener(stepDetector, sensor, SensorManager.SENSOR_DELAY_UI);
        stepDetector.setOnSensorChangeListener(new StepDetector.OnSensorChangeListener() {
            @Override
            public void onChange() {
                updateNotification("今日步数:" + StepDetector.CURRENT_STEP + " 步");
            }
        });
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (stepSensor == 0) {   //使用计步传感器
            int step = 0;
            //步数传感器==0  （重启过手机） 主要为了修改 previousStep 为 0
            if (isNewDay || event.values[0] == 0) {
                step = StepDetector.CURRENT_STEP;
                //用于判断是否为新的一天，如果是那么记录下计步传感器统计步数中的数据
                // 今天走的步数=传感器当前统计的步数-之前统计的步数
                previousStep = (int) event.values[0];    //得到传感器统计的步数
                isNewDay = false;
                save();
            } else {
                //取出之前的数据
                try {
                    List<StepData> list = DbUtils.getQueryByWhere(StepData.class, "today", new String[]{CURRENTDATE});
                    if (list != null && list.size() > 0) {
                        StepData data = list.get(0);
                        if (data != null) {
                            this.previousStep = Integer.valueOf(data.getPreviousStep());
                            step = Integer.valueOf(data.getStep());
                        }
                    }
                } catch (Exception e) {
                    LogUtils.writeLog(this, "1 today previousStep error:" + e.getMessage());
                }
            }
            if (event.values[0] < previousStep) {
                StepDetector.CURRENT_STEP = (int) event.values[0] + step;
            } else {
                StepDetector.CURRENT_STEP = (int) event.values[0] + step - previousStep;
            }
            previousStep = (int) event.values[0];
            save();


            LogUtils.writeLog(this, "1 step_detector step=" + (int) event.values[0] + " previousStep="
                    + previousStep + " current_step=" + StepDetector.CURRENT_STEP);
            //或者只是使用下面一句话，不过程序关闭后可能无法计步。根据需求可自行选择。
            //如果记录程序开启时走的步数可以使用这种方式——StepDetector.CURRENT_STEP++;
            //StepDetector.CURRENT_STEP++;
        } else if (stepSensor == 1) {
            StepDetector.CURRENT_STEP++;
            LogUtils.writeLog(this, "2 step_counter  current_step=" + StepDetector.CURRENT_STEP);
        }
        //更新状态栏信息
        updateNotification("今日步数：" + StepDetector.CURRENT_STEP + " 步");
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    /**
     * 保存数据
     */
    private void save() {
        int tempStep = StepDetector.CURRENT_STEP;
        List<StepData> list = DbUtils.getQueryByWhere(StepData.class, "today", new String[]{CURRENTDATE});
        if (list.size() == 0) {
            StepData data = new StepData();
            data.setStep(String.valueOf(tempStep));
            data.setToday(CURRENTDATE);
            data.setPreviousStep(String.valueOf(previousStep));
            DbUtils.insert(data);
        } else if (list.size() == 1) {
            StepData data = list.get(0);
            data.setStep(String.valueOf(tempStep));
            data.setPreviousStep(String.valueOf(previousStep));
            DbUtils.update(data);
        }
    }

    @Override
    public void onDestroy() {
        //取消前台进程
        stopForeground(true);
        DbUtils.closeDb();
        unregisterReceiver(mBatInfoReceiver);
        Intent intent = new Intent(this, StepService.class);
        startService(intent);
        super.onDestroy();
    }

    //  同步方法   得到休眠锁
    synchronized private PowerManager.WakeLock getLock(Context context) {
        if (mWakeLock != null) {
            if (mWakeLock.isHeld()) {
                mWakeLock.release();
                Log.v(TAG, "释放锁");
            }
            mWakeLock = null;
        }

        if (mWakeLock == null) {
            PowerManager mgr = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
            mWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, StepService.class.getName());
            mWakeLock.setReferenceCounted(true);
            Calendar c = Calendar.getInstance();
            c.setTimeInMillis((System.currentTimeMillis()));
            int hour = c.get(Calendar.HOUR_OF_DAY);
            if (hour >= 23 || hour <= 6) {
                mWakeLock.acquire(5000);
            } else {
                mWakeLock.acquire(300000);
            }
        }
        Log.v(TAG, "得到了锁");
        return (mWakeLock);
    }
}
